package com.xiaobawang.knowledge.spider.service.impl;

import com.dtflys.forest.http.ForestResponse;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.google.gson.reflect.TypeToken;
import com.xiaobawang.knowledge.spider.config.EmailConfig;
import com.xiaobawang.knowledge.spider.exception.BusinessException;
import com.xiaobawang.knowledge.spider.forest.GovernmentFinancialClient;
import com.xiaobawang.knowledge.spider.mapper.GovernmentRuleMapper;
import com.xiaobawang.knowledge.spider.model.dto.EmailDTO;
import com.xiaobawang.knowledge.spider.model.dto.GovernmentRuleListReqDTO;
import com.xiaobawang.knowledge.spider.model.entity.GovernmentFinancialItem;
import com.xiaobawang.knowledge.spider.service.EmailService;
import com.xiaobawang.knowledge.spider.service.GovernmentFinancialItemService;
import com.xiaobawang.knowledge.spider.util.DateUtil;
import com.xiaobawang.knowledge.spider.util.FileUtil;
import com.xiaobawang.knowledge.spider.util.GsonUtil;
import com.xiaobawang.knowledge.spider.util.HeaderUtil;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

import static com.xiaobawang.knowledge.spider.constant.GovernmentFinancialConstant.*;
import static com.xiaobawang.knowledge.spider.util.HeaderUtil.*;

/**
 * 政府规章信息(GovernmentRule)表服务实现类
 *
 * @author makejava
 * @since 2025-03-31 16:50:53
 */
@Service("governmentRuleService")
@Slf4j
public class GovernmentFinancialItemServiceImpl implements GovernmentFinancialItemService {

    @Resource
    GovernmentFinancialClient governmentFinancialClient;

    private final EmailConfig emailConfig;

    private final GovernmentRuleMapper governmentRuleMapper;

    private final EmailService emailService;

    public GovernmentFinancialItemServiceImpl(EmailConfig emailConfig,
                                              GovernmentRuleMapper governmentRuleMapper,
                                              EmailService emailService) {
        this.emailConfig = emailConfig;
        this.governmentRuleMapper = governmentRuleMapper;
        this.emailService = emailService;
    }

    /**
     * @author synhard
     * @description 获取国家金融监督管理总局规章
     * @date 2025/3/31 16:14
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void getGovernmentFinancialRulesFromWeb() {
        log.info("获取规章文件列表");
        // 获取规章列表信息
        List<GovernmentFinancialItem> governmentFinancialItemListFromWeb = this.getGovernmentRuleListFromWeb(ITEM_ID_FINANCIAL_RULES);
        // 过滤掉数据库中存在的
        governmentFinancialItemListFromWeb = this.filterExist(governmentFinancialItemListFromWeb);
        // 请求文件的字节数组
        List<byte[]> fileByteArrList = this.getGovernmentRuleFileByteArray(governmentFinancialItemListFromWeb);
        // 构造每个产品文件名称
        List<String> fileNameList = getGovernmentRuleFileName(governmentFinancialItemListFromWeb, "doc");
        // 发送邮件
        try  {
            List<File> zipParts = FileUtil.splitIntoZipFiles(fileByteArrList, fileNameList, 20 * 1024 * 1024);
            for (int i = 0; i < zipParts.size(); i++) {
                File     part     = zipParts.get(i);
                EmailDTO emailDTO = new EmailDTO();
                emailDTO.setSubject("国家金融监督管理总局规章(分卷" + (i + 1) + ")");
                emailDTO.setFile(part);
                emailDTO.setContent("此邮件为分卷压缩包，共" + zipParts.size() + "部分，需全部下载后解压");
                emailDTO.setTo(emailConfig.getSupervisorFileReceiver());
                emailDTO.setFrom(emailConfig.getFrom());
                emailService.sendEmail(emailDTO);
                part.delete();
            }
        } catch (Exception ex) {
            log.error("邮件发送失败", ex);
            throw new BusinessException("邮件发送失败: " + ex.getMessage());
        }
        // 将数据插入数据库中
        if (!governmentFinancialItemListFromWeb.isEmpty()) {
            this.governmentRuleMapper.insertBatch(governmentFinancialItemListFromWeb);
        }
    }

    /**
     * @author synhard
     * @description 获取国家金融监督管理总局行政规范性文件
     * @date 2025/3/31 16:14
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void getGovernmentFinancialAdministrationFromWeb() {
        log.info("获取行政规范性文件列表");
        // 获取行政规范性文件列表
        List<GovernmentFinancialItem> governmentFinancialItemListFromWeb = this.getGovernmentRuleListFromWeb(ITEM_ID_FINANCIAL_ADMINISTRATION);
        // 过滤掉数据库中存在的
        governmentFinancialItemListFromWeb = this.filterExist(governmentFinancialItemListFromWeb);
        // 请求文件的字节数组
        List<byte[]> fileByteArrList = this.getGovernmentAdministrationFileByteArray(governmentFinancialItemListFromWeb);
        // 构造每个产品文件名称
        List<String> fileNameList = getGovernmentRuleFileName(governmentFinancialItemListFromWeb, "pdf");
        // 发送邮件
        try  {
            List<File> zipParts = FileUtil.splitIntoZipFiles(fileByteArrList, fileNameList, 20 * 1024 * 1024);
            for (int i = 0; i < zipParts.size(); i++) {
                File     part     = zipParts.get(i);
                EmailDTO emailDTO = new EmailDTO();
                emailDTO.setSubject("国家金融监督管理总局行政规范性文件(分卷" + (i + 1) + ")");
                emailDTO.setFile(part);
                emailDTO.setContent("此邮件为分卷压缩包，共" + zipParts.size() + "部分，需全部下载后解压");
                emailDTO.setTo(emailConfig.getSupervisorFileReceiver());
                emailDTO.setFrom(emailConfig.getFrom());
                emailService.sendEmail(emailDTO);
                part.delete();
            }
        } catch (Exception ex) {
            log.error("邮件发送失败", ex);
            throw new BusinessException("邮件发送失败: " + ex.getMessage());
        }
        // 将数据插入数据库中
        if (!governmentFinancialItemListFromWeb.isEmpty()) {
            this.governmentRuleMapper.insertBatch(governmentFinancialItemListFromWeb);
        }
    }

    /**
     * @author synhard
     * @description 获取国家金融监督管理总局其他文件
     * @date 2025/3/31 16:14
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void getGovernmentFinancialOtherFromWeb() {
        log.info("获取其他文件列表");
        // 获取其他文件列表
        List<GovernmentFinancialItem> governmentFinancialItemListFromWeb = this.getGovernmentRuleListFromWeb(ITEM_ID_FINANCIAL_OTHER);
        // 过滤掉数据库中存在的
        governmentFinancialItemListFromWeb = this.filterExist(governmentFinancialItemListFromWeb);
        // 请求文件的字节数组
        List<byte[]> fileByteArrList = this.getGovernmentAdministrationFileByteArray(governmentFinancialItemListFromWeb);
        // 构造每个产品文件名称
        List<String> fileNameList = getGovernmentRuleFileName(governmentFinancialItemListFromWeb, "pdf");
        // 发送邮件
        try  {
            List<File> zipParts = FileUtil.splitIntoZipFiles(fileByteArrList, fileNameList, 20 * 1024 * 1024);
            for (int i = 0; i < zipParts.size(); i++) {
                File     part     = zipParts.get(i);
                EmailDTO emailDTO = new EmailDTO();
                emailDTO.setSubject("国家金融监督管理总局其他文件(分卷" + (i + 1) + ")");
                emailDTO.setFile(part);
                emailDTO.setContent("此邮件为分卷压缩包，共" + zipParts.size() + "部分，需全部下载后解压");
                emailDTO.setTo(emailConfig.getSupervisorFileReceiver());
                emailDTO.setFrom(emailConfig.getFrom());
                emailService.sendEmail(emailDTO);
                part.delete();
            }
        } catch (Exception ex) {
            log.error("邮件发送失败", ex);
            throw new BusinessException("邮件发送失败: " + ex.getMessage());
        }
        // 将数据插入数据库中
        if (!governmentFinancialItemListFromWeb.isEmpty()) {
            this.governmentRuleMapper.insertBatch(governmentFinancialItemListFromWeb);
        }
    }

    /**
     * @author synhard
     * @description 过滤掉数据库中存在的内容
     * @date 2025/6/9 09:10
     * @param governmentFinancialItemList 爬取到的数据
     * @return java.util.List<com.xiaobawang.knowledge.spider.model.entity.GovernmentFinancialItem>
     */
    private List<GovernmentFinancialItem> filterExist(List<GovernmentFinancialItem> governmentFinancialItemList) {
        List<GovernmentFinancialItem> res = new ArrayList<>();
        // 根据 docId 和 itemId 过滤数据
        for (GovernmentFinancialItem item : governmentFinancialItemList) {
            GovernmentFinancialItem query = new GovernmentFinancialItem();
            query.setDocId(item.getDocId());
            query.setItemId(item.getItemId());
            List<GovernmentFinancialItem> queryResult = this.governmentRuleMapper.queryAllByLimit(query);
            if (queryResult.isEmpty()) {
                res.add(item);
            }
        }
        return res;
    }

    /**
     * @author synhard
     * @description 获取政府规章文件字节数组
     * @date 2025/3/31 17:46
     * @param governmentFinancialItemList 政府规章列表
     * @return java.util.List<byte[]>
     */
    private List<byte[]> getGovernmentAdministrationFileByteArray(List<GovernmentFinancialItem> governmentFinancialItemList) {
        List<byte[]> fileByteArrList = new ArrayList<>();
        // 访问每个产品的条款的链接
        for (GovernmentFinancialItem governmentFinancialItem : governmentFinancialItemList) {
            // 获取链接，生成文件对应的字节数组
            try {
                byte[] bytes = this.governmentFinancialClient.getAdministrationFile(governmentFinancialItem.getDocId(), 2,
                        HeaderUtil.getHeader(GOVERNMENT_HOST, GOVERNMENT_HOST));
                fileByteArrList.add(bytes);
                Thread.sleep(3000L);
            } catch (Exception ex) {
                log.error(ex.getMessage());
                throw new BusinessException(ex.getMessage());
            }
        }
        return fileByteArrList;
    }

    /**
     * @author synhard
     * @description 获取政府规章文件字节数组
     * @date 2025/3/31 17:46
     * @param governmentFinancialItemList 政府规章列表
     * @return java.util.List<byte[]>
     */
    private List<byte[]> getGovernmentRuleFileByteArray(List<GovernmentFinancialItem> governmentFinancialItemList) {
        List<byte[]> fileByteArrList = new ArrayList<>();
        // 访问每个产品的条款的链接
        for (GovernmentFinancialItem governmentFinancialItem : governmentFinancialItemList) {
            // 获取链接，生成文件对应的字节数组
            try {
                byte[] bytes = this.governmentFinancialClient.getRuleFile(governmentFinancialItem.getDocId(),
                        HeaderUtil.getHeader(GOVERNMENT_HOST, GOVERNMENT_HOST));
                fileByteArrList.add(bytes);
                Thread.sleep(3000L);
            } catch (Exception ex) {
                log.error(ex.getMessage());
                throw new BusinessException(ex.getMessage());
            }
        }
        return fileByteArrList;
    }

    /**
     * @author synhard
     * @description 获取文件名称
     * @date 2025/3/31 20:29
     * @param governmentFinancialItemListFromWeb 政府规则列表
     * @return java.util.List<java.lang.String>
     */
    private List<String> getGovernmentRuleFileName(List<GovernmentFinancialItem> governmentFinancialItemListFromWeb, String fileSuffix) {
        List<String> fileNameList = new ArrayList<>();
        for (GovernmentFinancialItem governmentFinancialItem : governmentFinancialItemListFromWeb) {
            fileNameList.add(governmentFinancialItem.getDocSubtitle() + "(" + DateUtil.formatDate(governmentFinancialItem.getPublishDate(), DateUtil.DATE_FORMAT) + ")." + fileSuffix);
        }
        return fileNameList;
    }

    /**
     * @param
     * @return java.util.List<com.xiaobawang.knowledge.spider.model.entity.GovernmentRule>
     * @author synhard
     * @description 根据类型爬取全量国家金融监督管理总局文件
     * @date 2025/3/31 17:07
     */
    private List<GovernmentFinancialItem> getGovernmentRuleListFromWeb(int itemId) {
        Timer                         timer                    = new Timer();
        List<GovernmentFinancialItem> resultList               = new CopyOnWriteArrayList<>();
        AtomicInteger                 pageNo                   = new AtomicInteger(1);
        final int                     pageSize                 = 50;
        GovernmentRuleListReqDTO      governmentRuleListReqDTO = new GovernmentRuleListReqDTO();
        governmentRuleListReqDTO.setPageSize(String.valueOf(pageSize));
        governmentRuleListReqDTO.setItemId(itemId);
        CountDownLatch latch = new CountDownLatch(1);

        TimerTask task = new TimerTask() {
            @Override
            public void run() {
                try {
                    governmentRuleListReqDTO.setPageNo(pageNo.get());
                    ForestResponse<String> response = governmentFinancialClient.getRuleList(
                            governmentRuleListReqDTO,
                            HeaderUtil.getHeader(GOVERNMENT_HOST, GOVERNMENT_HOST)
                    );

                    if (!response.isSuccess()) {
                        timer.cancel();
                        throw new BusinessException("请求国家金融监管总局文件失败");
                    }

                    JsonObject json = GsonUtil.parseStringToJsonObject(response.getContent());
                    JsonObject data = GsonUtil.getAsJsonObjectSafety(json, "data");
                    JsonArray  list = GsonUtil.getAsJsonArraySafety(data, "lists");

                    if (list == null || list.isEmpty()) {
                        latch.countDown();
                        return;
                    }

                    List<GovernmentFinancialItem> subList = GsonUtil.getGson().fromJson(
                            list, new TypeToken<List<GovernmentFinancialItem>>() {
                            }.getType()
                    );
                    for (GovernmentFinancialItem governmentFinancialItem : subList) {
                        if (governmentFinancialItem.getDocSubtitle().contains("保险")) {
                            resultList.add(governmentFinancialItem);
                        }
                    }
                    pageNo.incrementAndGet();
                } catch (Exception e) {
                    log.error("分页请求异常", e);
                    timer.cancel();
                }
            }
        };

        timer.scheduleAtFixedRate(task, 0L, 1000L);

        try {
            latch.await(5, TimeUnit.MINUTES);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            log.error("线程被中断", e);
        } finally {
            timer.cancel();
        }

        return new ArrayList<>(resultList);
    }
}

